package com.klaus.ohMySpace.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.klaus.ohMySpace.conf.Configurator;
import com.klaus.ohMySpace.entity.BasicEntity;
import com.klaus.ohMySpace.entity.Note;
import com.klaus.ohMySpace.sys.common.ErrorCode;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;

/**
 * 将java对象转化成Json对象（可加上自定义json）， 并附带错误码和错误信息
 *
 * Created by Mklaus on 15/7/25.
 */
public class JsonUtil {

    private static final int successCode = Integer.parseInt(Configurator.getInstance().get("global.success.code"));


    public static void writeOK(HttpServletResponse resp){
        try {
            write(null,null,resp);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 业务成功调用
     * @param o     需要被Json序列化的对象
     * @param name  索引名
     * @param resp
     * @throws IOException
     */
    public static void write(Object o,String name,HttpServletResponse resp) throws IOException{
        try {
            write(successCode,null,o,name,null,resp);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    /**
     * 业务成功调用
     * @param o     需要被Json序列化的对象
     * @param name  索引名
     * @param add   附加json （连同被Json序列化的对象一起返回）
     * @param resp
     * @throws IOException
     */
    public static void write(Object o,String name,JSONObject add,HttpServletResponse resp) throws IOException{
        try {
            write(successCode,null,o,name,add,resp);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    /**
     * 业务失败返回
     * @param errcode   错误枚举（包含错误码，错误信息）
     * @param resp
     * @throws IOException
     */
    public static void writeError(ErrorCode errcode,HttpServletResponse resp) throws IOException{
        try {
            write(errcode.getCode(),errcode.getDesc(),null,null,null,resp);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    /**
     * 业务失败返回
     * @param errcode   错误码
     * @param errMsg    错误具体信息
     * @param resp
     * @throws IOException
     */
    public static void writeError(ErrorCode errcode,String errMsg,HttpServletResponse resp) throws IOException{
        try {
            if (errMsg == null){
                errMsg = errcode.getDesc();
            }else {
                errMsg = errcode.getDesc() + " : " + errMsg;
            }
            write(errcode.getCode(),errMsg,null,null,null,resp);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    /**
     * 业务失败返回
     * @param errcode   错误码（int）
     * @param errMsg    错误信息
     * @param resp
     * @throws IOException
     */
    public static void writeError(int errcode,String errMsg,HttpServletResponse resp) throws IOException{
        try {

            write(errcode,errMsg,null,null,null,resp);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    /**
     * return FORMAT :
     * {
     *     errCode : -1,
     *     errMsg  : need Login,
     *     data    : {jsonize object}
     * }
     *
     */
    private static void write(int msgcode,String errMsg,Object o,String name,JSONObject add,HttpServletResponse resp) throws IOException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        resp.setContentType("application/json; charset=utf-8");
        resp.setCharacterEncoding("utf-8");
        PrintWriter out = resp.getWriter();

        JSONArray  dataArray    = new JSONArray();
        JSONObject data         = (add != null) ? add : new JSONObject();
        JSONObject result       = new JSONObject();

        result.put("errcode",msgcode);
        if (errMsg != null)
            result.put("errMsg",errMsg);


        if (o instanceof Collection) {
            dataArray = jsonizeCollect((Collection) o);
            data.put(name, dataArray);
        }else if (o instanceof BasicEntity){
            data = jsonize((BasicEntity)o,data);
        }else if (name != null){
            add.put(name,o);
            data = add;
        }

        if (msgcode >= 0)
            result.put("data",data);

        System.out.println(result.toJSONString());

        out.print(result.toJSONString());

        out.flush();
        out.close();
    }

    /**
     * 序列化类集
     * @param
     * @return
     */
    public static JSONArray jsonizeCollect(Collection c) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        JSONArray jsonArray = new JSONArray();

        for (Object o : c){
            jsonArray.add(jsonize((BasicEntity)o,null));
        }

        return jsonArray;
    }


    /**
     * 利用反射获取类的所有属性，并转化成Json
     */
    public static JSONObject jsonize(BasicEntity object,JSONObject add) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        JSONObject json = (add != null) ? add : new JSONObject();

        // 父类属性需要自己添加
        json.put("id"           ,object.getId());
        json.put("is_deleted"   ,object.getIsDelete());
        json.put("create_time"  ,object.getCreated_time());
        json.put("modify_time"  ,object.getModify_time());

        // 获取实体类的所有属性，返回Field数组
        Field[] field =object.getClass().getDeclaredFields();

        // 遍历所有属性
        for (int j = 0; j < field.length; j++) {

            //获取属性的名字
            String name = field[j].getName();
            //获取属性的类型
            String type = field[j].getGenericType().toString();
            //首字母大写 结合getter,setter使用
            String Mname = name.substring(0,1).toUpperCase()+name.substring(1);


            /**
             * 指定项目包中的类时，只需put id,避免循环引用
             *
             * type example
             * 类type   : class com.klaus.ohMySpace.entity.Note
             * 类集type : java.util.Set<com.klaus.ohMySpace.entity.Note>
             */
            if (type.contains("com.klaus.ohMySpace.entity")){
                if (type.startsWith("java.util")){
                    Method m = object.getClass().getMethod("get"+Mname);
                    JSONArray ids = new JSONArray();
                    if (( (Collection)(m.invoke(object)) ).size() > 0) {
                        for (BasicEntity be : (Collection<BasicEntity>)(m.invoke(object))){
                            ids.add(be.getId());
                        }
                        json.put(name, ids);
                    }
                }else {
                    Method m = object.getClass().getMethod("get" + Mname);
                    if (m.invoke(object) != null) {
                        int id = ((BasicEntity) (m.invoke(object))).getId();
                        json.put(name, id);
                    }
                }
            }else {
                Method m = object.getClass().getMethod("get"+Mname);
                String value = ( m.invoke(object) != null) ? m.invoke(object).toString(): "";    //调用getter方法获取属性值
                json.put(name,value);
            }
        }

        return json;
    }
}
